package redtask

import (
	"context"
	dgctx "github.com/darwinOrg/go-common/context"
	dglogger "github.com/darwinOrg/go-logger"
	"github.com/hibiken/asynq"
	"time"
)

type InitTaskRequest struct {
	TaskType  string
	Payload   []byte
	TaskId    string
	Queue     string
	Group     string
	MaxRetry  int
	Timeout   time.Duration
	ProcessIn time.Duration
	ProcessAt time.Time
	Retention time.Duration
	UniqueTTL time.Duration
	Deadline  time.Time
}

type TaskHandler func(dc *dgctx.DgContext, payload []byte) error

func InitTask(dc *dgctx.DgContext, req *InitTaskRequest) (string, error) {
	var opts []asynq.Option
	if req.TaskId != "" {
		opts = append(opts, asynq.TaskID(req.TaskId))
	}
	if req.Queue != "" {
		opts = append(opts, asynq.Queue(req.Queue))
	}
	if req.Group != "" {
		opts = append(opts, asynq.Group(req.Group))
	}
	if req.MaxRetry > 0 {
		opts = append(opts, asynq.MaxRetry(req.MaxRetry))
	}
	if req.Timeout > 0 {
		opts = append(opts, asynq.Timeout(req.Timeout))
	}
	if req.ProcessIn > 0 {
		opts = append(opts, asynq.ProcessIn(req.ProcessIn))
	}
	if !req.ProcessAt.IsZero() {
		opts = append(opts, asynq.ProcessAt(req.ProcessAt))
	}
	if req.Retention > 0 {
		opts = append(opts, asynq.Retention(req.Retention))
	}
	if req.UniqueTTL > 0 {
		opts = append(opts, asynq.Unique(req.UniqueTTL))
	}
	if !req.Deadline.IsZero() {
		opts = append(opts, asynq.Deadline(req.Deadline))
	}

	var task *asynq.Task
	if len(opts) > 0 {
		task = asynq.NewTask(req.TaskType, req.Payload, opts...)
	} else {
		task = asynq.NewTask(req.TaskType, req.Payload)
	}

	info, err := asynqClient.Enqueue(task)
	if err != nil {
		dglogger.Errorf(dc, "could not enqueue task: %v", err)
		return "", err
	}
	dglogger.Infof(dc, "enqueued task: id: %s | queue: %s", info.ID, info.Queue)
	return info.ID, nil
}

func RegisterHandler(dc *dgctx.DgContext, taskType string, handler TaskHandler) {
	asynqMux.HandleFunc(taskType, func(ctx context.Context, task *asynq.Task) error {
		dc.SetInnerContext(ctx)
		return handler(dc, task.Payload())
	})
}
